import backtrader as bt
import logging
from datetime import datetime
from .DbOprate import DbOprate

class TDXFunctions:
    """通达信常用函数工具类"""
    
    @staticmethod
    def HHV(data, period):
        """最高值函数 - 返回指定周期内的最大值"""
        if len(data) < period:
            return max(data) if len(data) > 0 else 0
        return max(data.get(ago=0, size=period))
    
    @staticmethod
    def LLV(data, period):
        """最低值函数 - 返回指定周期内的最小值"""
        if len(data) < period:
            return min(data) if len(data) > 0 else 0
        return min(data.get(ago=0, size=period))
    
    @staticmethod
    def CROSS_simple(a_prev, a_curr, b_prev, b_curr):
        """简化版交叉函数，用于数值比较"""
        return (a_prev < b_prev) and (a_curr >= b_curr)
    
    @staticmethod
    def FILTER(signals, period):
        """
        过滤函数 - 在指定周期内，同一个条件只能成立一次
        返回过滤后的完整信号列表
        """
        if len(signals) == 0:
            return []
        
        filtered_signals = [False] * len(signals)
        
        # 从前往后处理每个信号
        for i in range(len(signals)):
            if not signals[i]:
                continue
            
            # 检查从当前位置往前推period周期内是否已经有True信号
            start_idx = max(0, i - period + 1)
            has_recent_true = False
            
            for j in range(start_idx, i):
                if filtered_signals[j]:
                    has_recent_true = True
                    break
            
            # 如果在指定周期内没有其他True信号，则当前信号成立
            if not has_recent_true:
                filtered_signals[i] = True
        
        return filtered_signals
    
    @staticmethod
    def BARSLAST(condition_signals):
        """
        上一次条件成立距今的周期数
        返回距离最近一次True信号的周期数（从0开始）
        """
        if len(condition_signals) == 0:
            return 0
        
        # 从后往前查找最近的True信号
        for i in range(len(condition_signals)):
            idx = len(condition_signals) - 1 - i
            if condition_signals[idx]:
                return i
        return len(condition_signals)  # 如果从未找到，则返回最大距离
    
    @staticmethod
    def REF(data, periods):
        """
        引用函数 - 引用若干周期前的数据
        periods: 周期数（正数表示往前推）
        """
        if len(data) <= periods or periods < 0:
            return data[0] if len(data) > 0 else 0
        return data[-periods] if periods > 0 else data[0]


class TDXHighPointStrategy(bt.Strategy):
    """
    通达信高点策略
    G1:=40;
    G2:=20;
    X_10: CLOSE=HHV(CLOSE,G1);{收盘价是否40日最高收盘价}
    X_10_1: CROSS(0.8,X_10);{收盘价是否40日最高收盘价}
    X_10_2: FILTER(CROSS(0.8,X_10),G2);{收盘价是否40日最高收盘价}
    X_11: BARSLAST(FILTER(CROSS(0.8,X_10),G2))+1;{距离最近一次"股价从创阶段新高后回落"的信号，已经过去了多少根K线}
    GD:= REF(HIGH,X_11);{短期高点开始画虚线}
    F:GD!=REF(GD,1);
    """
    params = (
        ('g1', 40),      # 40日周期
        ('g2', 20),      # 20日周期 - 过滤周期
    )

    def __init__(self):
        self.data_close = self.datas[0].close
        self.data_high = self.datas[0].high
        self.tdx = TDXFunctions()

        # 存储历史数据
        self.x_10_history = []
        self.x_10_1_history = []
        self.x_10_2_history = []
        self.x_11_history = []
        self.gd_history = []
        self.f_history = []

        # 设置日志
        self.setup_logging()

    def setup_logging(self):
        """设置日志配置"""
        self.logger = logging.getLogger(f'TDXHighPointStrategy_{self.datas[0]._name}')
        self.logger.setLevel(logging.INFO)
        
        # 创建文件处理器
        log_filename = f'tdx_highpoint_strategy_{self.datas[0]._name}_{datetime.now().strftime("%Y%m%d")}.log'
        file_handler = logging.FileHandler(log_filename, encoding='utf-8')
        file_handler.setLevel(logging.INFO)
        
        # 创建格式器
        formatter = logging.Formatter('%(asctime)s - %(message)s')
        file_handler.setFormatter(formatter)
        
        # 添加处理器
        if not self.logger.handlers:
            self.logger.addHandler(file_handler)

    def log_daily_params(self, params_dict):
        """记录每日参数到日志文件"""
        log_msg = "\n" + "="*80 + "\n"
        log_msg += f"日期: {params_dict['date']}\n"
        log_msg += f"股票代码: {params_dict['stock_code']}\n"
        log_msg += "-"*80 + "\n"
        log_msg += f"CLOSE: {params_dict['close']:.4f}\n"
        log_msg += f"HIGH: {params_dict['high']:.4f}\n"
        log_msg += f"HHV(CLOSE,{self.p.g1}): {params_dict['hhv_close']:.4f}\n"
        log_msg += f"X_10 (CLOSE=HHV(CLOSE,{self.p.g1})): {params_dict['x_10']} ({params_dict['x_10_numeric']})\n"
        log_msg += f"X_10_1 (CROSS(0.8,X_10)): {params_dict['x_10_1']}\n"
        log_msg += f"X_10_2 (FILTER(CROSS(0.8,X_10),{self.p.g2})): {params_dict['x_10_2']}\n"
        log_msg += f"X_11 (BARSLAST(FILTER(...))+1): {params_dict['x_11']}\n"
        log_msg += f"GD (REF(HIGH,X_11)): {params_dict['gd']:.4f}\n"
        log_msg += f"F (GD!=REF(GD,1)): {params_dict['f']}\n"
        log_msg += "="*80 + "\n"
        
        self.logger.info(log_msg)
        
        # 如果有卖出信号，额外记录
        if params_dict['f'] and params_dict['x_11'] > 1:
            signal_msg = f"\n*** 卖出信号 *** 价格: {params_dict['close']:.4f} ***\n"
            self.logger.info(signal_msg)

    def next(self):
        current_date = self.datas[0].datetime.date(0)
        current_price = float(self.data_close[0])
        current_high = float(self.data_high[0])

        # ========== 严格按照通达信公式顺序计算 ==========
        
        # X_10: CLOSE=HHV(CLOSE,G1) - 收盘价是否40日最高收盘价
        hhv_value = self.tdx.HHV(self.data_close, self.p.g1)
        x_10_value = abs(current_price - hhv_value) < 0.0001
        x_10_numeric = int(x_10_value)
        self.x_10_history.append(x_10_numeric)
        
        # X_10_1: CROSS(0.8,X_10) - 检测 X_10 从 0 变为 1
        x_10_1_value = False
        if len(self.x_10_history) >= 2:
            x_10_prev = self.x_10_history[-2]
            x_10_curr = self.x_10_history[-1]
            # CROSS(0.8, X_10) 意味着 0.8 上穿 X_10
            # 即 0.8_prev < X_10_prev 且 0.8_curr >= X_10_curr
            # 由于0.8是常数0.8，实际是检测 X_10 从 0 变为 1
            x_10_1_value = (0.8 < x_10_prev) and (0.8 >= x_10_curr)
        self.x_10_1_history.append(x_10_1_value)
        
        # X_10_2: FILTER(CROSS(0.8,X_10),G2)
        x_10_2_value = False
        if len(self.x_10_1_history) > 0:
            # 应用FILTER函数
            all_filtered = self.tdx.FILTER(self.x_10_1_history, self.p.g2)
            x_10_2_value = all_filtered[-1] if len(all_filtered) > 0 else False
        self.x_10_2_history.append(x_10_2_value)
        
        # X_11: BARSLAST(FILTER(CROSS(0.8,X_10),G2))+1
        barslast_value = self.tdx.BARSLAST(self.x_10_2_history)
        x_11_value = barslast_value + 1
        self.x_11_history.append(x_11_value)
        
        # GD: REF(HIGH,X_11)
        gd_value = self.tdx.REF(self.data_high, x_11_value)
        self.gd_history.append(gd_value)
        
        # F: GD!=REF(GD,1)
        f_value = False
        if len(self.gd_history) >= 2:
            gd_prev = self.gd_history[-2]
            gd_curr = self.gd_history[-1]
            f_value = abs(gd_curr - gd_prev) > 0.0001
        self.f_history.append(f_value)
        
        # ========== 记录所有参数到日志 ==========
        daily_params = {
            'date': current_date.isoformat(),
            'stock_code': self.datas[0]._name,
            'close': current_price,
            'high': current_high,
            'hhv_close': hhv_value,
            'x_10': x_10_value,
            'x_10_numeric': x_10_numeric,
            'x_10_1': x_10_1_value,
            'x_10_2': x_10_2_value,
            'x_11': x_11_value,
            'gd': gd_value,
            'f': f_value
        }
        
        self.log_daily_params(daily_params)
        
        # ========== 卖出信号判断 ==========
        # F为True表示GD发生变化，通常意味着X_11从1变为其他值
        # 这表示股价从创阶段新高后的回落信号
        if f_value :
            print(f'{current_date} - *** 卖出信号 *** 价格: {current_price:.4f}')
            
            # 存储信号到数据库
            try:
                result = {
                    'strategy': 'TDXHighPointStrategy',
                    'stock_code': self.datas[0]._name,
                    'op_act': 'sell_signal',
                    'op_price': current_price,
                    'op_num': 100,
                    'op_comm': 0.0,
                    'op_dt': current_date.isoformat(),
                    'reason': '阶段性高点卖出信号',
                    'x_11_value': float(x_11_value),
                    'gd_value': float(gd_value),
                    'detail_info': f'CLOSE={current_price}, X_10={x_10_numeric}, X_11={x_11_value}'
                }
                DbOprate.save_result_to_mysql(result)
                print(f'{current_date} - *** 卖出信号已存入数据库 ***')
            except Exception as e:
                print(f'{current_date} - *** 数据库存储失败: {str(e)} ***')

    def stop(self):
        print(f'=== TDX高点策略执行完成 ===')
        print(f'日志文件已保存到: tdx_highpoint_strategy_{self.datas[0]._name}_*.log')
